import { Message, Notification } from 'element-ui'
import { imgUrlQ } from '@/api/apiTool'
import { getTaggingMsgByObjid } from "@/api/front/tag"
import { getImgFixCanvas, getScaleMouseOffset, getOriginImgPoint } from "./mathFun"
import rectangleTag from "./rectangleTag"
import roundTag from "./roundTag"
import polygonTag from "./polygonTag"
import Point from "./point"
export default class View {
    //标注id
    taggingObjid = "";
    //canvas元素ID
    elementId = "";
    //canvas element
    el = null;
    //canvas context
    ctx = null;
    //底图
    baseImg = null;
    //标注数据
    taggingData = null;
    //数据库标注信息【实例化后使用】
    databaseData = null;
    //临时标注数据
    tempTaggingData = null;
    //缩放
    scale = [1, 1];
    //缩放极限
    maxScale = [0.1, 5];
    //偏移量
    offset = [0, 0];
    //定时器
    interval = null;
    //多少秒刷新一次
    time = 16;
    //拖动
    dragEnable = true;
    //是否处于标注状态当中
    beingTag = false;
    //标注工具类型
    toolType = 0;
    //标注临时id
    tempIds = {
        rect: "",
        round: "",
        polygon: ""
    };
    //标注属性配置
    taggingConfig = {
        color: '',
        width: 0,
        highLightColr: "rgba(3, 244, 39, 1)"
    };
    //拖动数据
    dragData = [];
    //查看模式
    showType = false;
    //查看模式鼠标移动回调事件
    showTypeCallback = null;
    //构造函数
    constructor(elementId, taggingObjid, taggingConfig) {
        let el = document.getElementById(elementId);
        if (el != null && el.tagName === "CANVAS") {
            this.elementId = elementId
            this.el = el
            this.ctx = el.getContext("2d")
            this.taggingObjid = taggingObjid
            this.taggingConfig.color = taggingConfig.color || "rgba(5, 158, 234, 1)"
            this.taggingConfig.width = taggingConfig.width || 2
            this.showType = taggingConfig.showType || false;
            getTaggingMsgByObjid({ objid: taggingObjid }, (res) => {
                if (res.code == 200) {
                    //数据库标注数据
                    this.databaseData = res.data.taggingData
                        //临时标注数据
                    this.tempTaggingData = {
                        rect: [],
                        round: [],
                        polygon: []
                    };
                    //底图信息
                    this.baseImg = res.data.img || { url: '', width: '', height: '', el: null };
                    this.baseImg.url = imgUrlQ + this.baseImg.url;
                    //初始化
                    this.init();
                    //定时器
                    this.interval = setInterval(this.drawAllPage.bind(this), this.time)
                } else {
                    Message.error(res.msg + " 暂无法渲染素材信息")
                }
            })
        } else {
            window.console.error(`There is no canvas element ID named ${elementId}`)
        }
    }

    //初始化
    init() {
        //自适应宽高
        this.autoFixWH();
        //调整底图位置
        this.fixBaseImgPosition();
        //加载底图文件element
        this.initBaseImgEl();
        //绘制底图
        this.loadBaseImg();
        //注册基本事件
        this.registerBaseEvent();
        //实例化数据库标注信息
        this.initTaggingData(this.databaseData)
    }

    //一直刷新页面
    drawAllPage() {
        this.clearAllCanvas()
        this.loadBaseImg()
        this.drawAllTaggingPage()
    }

    //删除定时器
    deleteInterval() {
        if (this.interval) {
            window.clearInterval(this.interval)
        }
    }

    //初始化原标注数据
    initTaggingData(data) {
        this.taggingData = {
            rect: [],
            round: [],
            polygon: []
        }
        let position = this.baseImg.position
        Object.keys(data).forEach((key) => {
            data[key].map((item) => {
                let tempPoint = JSON.parse(item.points)
                let config = {
                    color: item.color,
                    width: item.width,
                    createdT: item.createdT,
                    zhcn: item.zhcn,
                    zy: item.zy,
                    title: item.title,
                    objid: item.objid
                }
                if (key == "rect") {
                    let recT = new rectangleTag(new Point(tempPoint[0], tempPoint[1]), new Point(tempPoint[2], tempPoint[3]), position, config)
                    this.taggingData[key].push(recT)
                } else if (key == "round") {
                    let round = new roundTag(new Point(tempPoint[0], tempPoint[1]), new Point(tempPoint[2], tempPoint[3]), position, config)
                    this.taggingData[key].push(round)
                } else if (key == "polygon") {
                    tempPoint = tempPoint.map((point) => {
                        return new Point(point[0], point[1])
                    })
                    let polygon = new polygonTag(tempPoint, position, config)
                    this.taggingData[key].push(polygon)
                }
            })
        })

    }

    //绘制所有标注信息
    drawAllTaggingPage() {
        //原始数据
        Object.keys(this.taggingData).forEach((key) => {
            if (this.taggingData[key] && this.taggingData[key] instanceof Array) {
                this.taggingData[key].map((item) => {
                    if (key == "rect") {
                        this.drawRectangle(item)
                    } else if (key == "round") {
                        this.drawRound(item)
                    } else if (key == "polygon") {
                        this.drawPolygon(item)
                    }
                })
            }
        })

        //标注临时数据
        Object.keys(this.tempTaggingData).forEach((key) => {
            if (this.tempTaggingData[key] && this.tempTaggingData[key] instanceof Array) {
                this.tempTaggingData[key].map((item) => {
                    if (key == "rect") {
                        this.drawRectangle(item)
                    } else if (key == "round") {
                        this.drawRound(item)
                    } else if (key == "polygon") {
                        this.drawPolygon(item)
                    }
                })
            }
        })
    }

    //调整所有标注点位置
    fixAllTaggingPosition() {
        let position = this.baseImg.position;
        //原始数据
        Object.keys(this.taggingData).forEach((key) => {
            if (this.taggingData[key] && this.taggingData[key] instanceof Array) {
                this.taggingData[key].map((item) => {
                    item.dragAutoReset(position)
                })
            }
        })

        //标注临时数据
        Object.keys(this.tempTaggingData).forEach((key) => {
            if (this.tempTaggingData[key] && this.tempTaggingData[key] instanceof Array) {
                this.tempTaggingData[key].map((item) => {
                    item.dragAutoReset(position)
                })
            }
        })
    }

    //绘制矩形框
    drawRectangle(rec) {
        if (rec.show) {
            this.ctx.beginPath();
            this.ctx.lineWidth = rec.width;
            this.ctx.strokeStyle = rec.highLight ? this.taggingConfig.highLightColr : rec.color;
            let [x1, y1, w, h] = rec.drawPosition;
            this.ctx.rect(x1, y1, w, h);
            this.ctx.stroke();
        }
        if (rec.showTitle) {
            let [x1, y1, x2, y2] = rec.border
                // this.ctx.fillStyle = "white"
                // let chinese = rec.title.match(/[\u4e00-\u9fa5]/g) ? rec.title.match(/[\u4e00-\u9fa5]/g).join("") : "";
                // this.ctx.fillRect(x1 - 5, y2, (rec.title.length - chinese.length) * 10 + chinese.length * 25 + 10, 25)
            this.ctx.font = "18px Arial"
            this.ctx.fillStyle = "black"
            this.ctx.fillText(rec.title, x1, y2 + 20);
        }
    }

    //绘制圆形框
    drawRound(round) {
        if (round.show) {
            this.ctx.beginPath();
            this.ctx.lineWidth = round.width;
            this.ctx.strokeStyle = round.highLight ? this.taggingConfig.highLightColr : round.color;
            let [COCX, COCY, R] = round.drawPosition;
            this.ctx.arc(COCX, COCY, R, 0, 2 * Math.PI);
            this.ctx.stroke();
        }
        if (round.showTitle) {
            let [x1, y1, x2, y2] = round.border
                // this.ctx.fillStyle = "white"
                // let chinese = round.title.match(/[\u4e00-\u9fa5]/g) ? round.title.match(/[\u4e00-\u9fa5]/g).join("") : "";
                // this.ctx.fillRect(x1 - 5, y2, (round.title.length - chinese.length) * 10 + chinese.length * 25 + 10, 25)
            this.ctx.font = "18px Arial"
            this.ctx.fillStyle = "black"
            this.ctx.fillText(round.title, x1 + (x2 - x1) / 3, y2 + 20);
        }
    }

    //绘制多边形
    drawPolygon(polygon) {
        if (polygon.show) {
            this.ctx.beginPath();
            this.ctx.lineWidth = polygon.width;
            this.ctx.strokeStyle = polygon.highLight ? this.taggingConfig.highLightColr : polygon.color;
            if (polygon.vitural.show) {
                this.ctx.arc(polygon.drawPosition[0][0], polygon.drawPosition[0][1], 2, 0, 2 * Math.PI);
            }
            this.ctx.moveTo(polygon.drawPosition[0][0], polygon.drawPosition[0][1]);
            polygon.drawPosition.map((item, key) => {
                if (key) {
                    this.ctx.lineTo(item[0], item[1])
                }
            });
            if (polygon.vitural.show) {
                this.ctx.lineTo(polygon.vitural.point[0], polygon.vitural.point[1])
            }
            this.ctx.closePath();
            this.ctx.stroke();
        }
        if (polygon.showTitle) {
            let [x1, y1, x2, y2] = polygon.border
                // this.ctx.fillStyle = "white"
                // let chinese = polygon.title.match(/[\u4e00-\u9fa5]/g) ? polygon.title.match(/[\u4e00-\u9fa5]/g).join("") : "";
                // this.ctx.fillRect(x1 - 5, y2, (polygon.title.length - chinese.length) * 10 + chinese.length * 25 + 10, 25)
            this.ctx.font = "18px Arial"
            this.ctx.fillStyle = "black"
            this.ctx.fillText(polygon.title, x1, y2 + 20);
        }
    }

    //初始化底图文件element并
    initBaseImgEl() {
        this.baseImg.el = new Image()
        this.baseImg.el.src = this.baseImg.url + "?t=" + new Date().getTime();
        this.baseImg.el.setAttribute('crossOrigin', 'anonymous');
    }

    //根据屏幕自动适应宽高
    autoFixWH(defaultWH = false) {
        if (this.showType) {
            this.el.width = this.el.parentElement.offsetWidth
        } else {
            this.el.width = this.el.parentElement.offsetWidth - 400
        }
        this.el.height = this.el.parentElement.offsetHeight
        if (defaultWH) {
            this.scale = [1, 1]
            this.dragData = [0, 0]
            this.offset = [0, 0]
            this.dragEnable = true
        }
    }

    //调整底图位置
    fixBaseImgPosition() {
        let [startX, startY, width, height] = getImgFixCanvas(this.el.width, this.el.height, this.baseImg.width, this.baseImg.height, this.scale, this.offset)
        this.baseImg.position = [startX, startY, width, height]
    }

    //绘制底图
    loadBaseImg() {
        let [startX, startY, width, height] = this.baseImg.position
        if (this.baseImg.loaded) {
            this.ctx.drawImage(this.baseImg.el, startX, startY, width, height)
        } else {
            this.baseImg.el.onload = () => {
                this.ctx.drawImage(this.baseImg.el, startX, startY, width, height)
                this.baseImg.loaded = true
            }
            this.baseImg.el.onerror = () => {
                Message.error("底图加载失败")
            }
        }
    }

    //窗口变化事件
    windowResize(e) {
        this.clearAllCanvas();
        this.autoFixWH();
        this.loadBaseImg();
        this.fixBaseImgPosition();
        this.fixAllTaggingPosition();
    }

    //滚轮事件
    mouseWheelEvent(e) {
        let down = true
        e = e || window.event;
        if (e.wheelDelta) { //判断浏览器IE，谷歌滑轮事件               
            if (e.wheelDelta < 0) { //当滑轮向上滚动时  
                down = false
            }
        } else if (e.detail) { //Firefox滑轮事件  
            if (e.detail < 0) { //当滑轮向上滚动时  
                down = false
            }
        }
        this.scale[0] += (down ? 0.1 : -0.1)
        this.scale[1] += (down ? 0.1 : -0.1)
        this.scale[0] = this.scale[0] > 0 ? (this.scale[0] < this.maxScale[1] ? this.scale[0] : this.maxScale[1]) : this.maxScale[0]
        this.scale[1] = this.scale[1] > 0 ? (this.scale[1] < this.maxScale[1] ? this.scale[1] : this.maxScale[1]) : this.maxScale[0]
        let tempOffset = getScaleMouseOffset(this.el.width / 2, this.el.height / 2, e.offsetX, e.offsetY, this.offset, this.baseImg.position, this.scale)
        this.offset[0] = tempOffset[0]
        this.offset[1] = tempOffset[1]
        this.fixBaseImgPosition();
        this.fixAllTaggingPosition();
    }

    //鼠标按下事件
    mouseDownEvent(e) {
        let position = this.baseImg.position;
        let mouseW = e.offsetX;
        let mouseH = e.offsetY;
        let openMoveDownEvent = true
        if (this.dragEnable && !this.beingTag) { //拖动
            if (mouseW >= position[0] && mouseW <= position[0] + position[2] && mouseH >= position[1] && mouseH <= position[3]) {
                this.el.style.cursor = "move";
                this.dragData = [mouseW, mouseH];
            } else {
                openMoveDownEvent = false
                Notification({ title: '提示', message: '请将鼠标移至图片上，然后拖动', duration: 2000 })
            }
        } else if (this.toolType == 1) { //矩形标注

            let recT = new rectangleTag(new Point(getOriginImgPoint(mouseW, mouseH, position)), new Point(getOriginImgPoint(mouseW, mouseH, position)), position, this.taggingConfig);
            this.tempTaggingData.rect.push(recT)
            this.tempIds.rect = recT.id
        } else if (this.toolType == 2) { //圆形标注
            let roundT = new roundTag(new Point(getOriginImgPoint(mouseW, mouseH, position)), new Point(getOriginImgPoint(mouseW, mouseH, position)), position, this.taggingConfig);
            this.tempTaggingData.round.push(roundT)
            this.tempIds.round = roundT.id
        } else if (this.toolType == 3) { //多边形标注
            if (!this.tempIds.polygon) {
                let poly = new polygonTag([new Point(getOriginImgPoint(mouseW, mouseH, position))], position, this.taggingConfig, true)
                this.tempTaggingData.polygon.push(poly)
                this.tempIds.polygon = poly.id
            } else {
                this.tempTaggingData.polygon.map((item) => {
                    if (item.id == this.tempIds.polygon) {
                        item.addPoint(new Point(getOriginImgPoint(mouseW, mouseH, position)), position)
                    }
                })
            }

        }

        //移动和停止移动事件注册
        if (openMoveDownEvent) {
            this.el.addEventListener("mousemove", this.mouseMoveEvent_, false)
            if (this.toolType != 3) {
                this.el.addEventListener("mouseup", this.mouseMoveDownEvent_, false)
            } else {
                window.addEventListener("keydown", this.keyDownEvent_, false)
            }
        }
    }

    //鼠标移动事件
    mouseMoveEvent(e) {
        let position = this.baseImg.position
        if (this.dragEnable && !this.beingTag) { //拖动
            this.offset[0] += (e.offsetX - this.dragData[0])
            this.offset[1] += (e.offsetY - this.dragData[1])
            this.dragData[0] = e.offsetX
            this.dragData[1] = e.offsetY
            this.fixBaseImgPosition();
            this.fixAllTaggingPosition();
        } else if (this.toolType == 1) { //矩形标注
            this.tempTaggingData.rect.map((item) => {
                if (item.id == this.tempIds.rect) {
                    let [x1, y1, x2, y2] = item.positionP;
                    [x2, y2] = getOriginImgPoint(e.offsetX, e.offsetY, position);
                    item.resetPoint(x1, y1, x2, y2, position);
                }
            })
        } else if (this.toolType == 2) { //圆形标注
            this.tempTaggingData.round.map((item) => {
                if (item.id == this.tempIds.round) {
                    let [x1, y1, x2, y2] = item.positionP;
                    [x2, y2] = getOriginImgPoint(e.offsetX, e.offsetY, position);
                    item.resetPoint(x1, y1, x2, y2, position);
                }
            })
        }

        if (this.tempIds.polygon) { //多边形标注
            this.tempTaggingData.polygon.map((item) => {
                if (item.id == this.tempIds.polygon) {
                    let [x1, y1] = getOriginImgPoint(e.offsetX, e.offsetY, position);
                    item.resetVitural(x1, y1, position)
                }
            })
        }
    }

    //可移除的鼠标移动事件
    mouseMoveEvent_ = this.mouseMoveEvent.bind(this)

    //键盘按下事件
    keyDownEvent(e) {
        if (this.toolType == 3 && e.keyCode == 88) { //结束多边形标注
            this.tempTaggingData.polygon.map((item) => {
                if (item.id == this.tempIds.polygon) {
                    item.closeVitural();
                }
            })
            this.tempIds.polygon = "";
            this.el.removeEventListener("mousemove", this.mouseMoveEvent_, false)
            window.removeEventListener("keydown", this.keyDownEvent_, false)
        }
    }

    //可移除的键盘按下事件
    keyDownEvent_ = this.keyDownEvent.bind(this)

    //鼠标停止移动
    mouseMoveDownEvent(e) {
        //移除鼠标移动停止移动事件
        let stopMove = true
        if (this.dragEnable && !this.beingTag) { //拖动
            this.el.style.cursor = "default"
        } else if (this.toolType == 1) { //矩形标注
            // this.tempIds.rect = "";
        } else if (this.toolType == 2) { //圆形标注
            // this.tempIds.round = "";
        }

        if (stopMove) {
            this.el.removeEventListener("mousemove", this.mouseMoveEvent_, false)
            this.el.removeEventListener("mouseup", this.mouseMoveDownEvent_, false)
        }
    }

    //可移除的鼠标停止移动
    mouseMoveDownEvent_ = this.mouseMoveDownEvent.bind(this)

    //检测鼠标是否在标注中的鼠标移动事件
    checkPointMouseMoveEvent(e) {
        let mouseW = e.offsetX;
        let mouseH = e.offsetY;
        let hasInter = false
        Object.keys(this.taggingData).forEach((key) => {
            if (this.taggingData[key] && this.taggingData[key] instanceof Array) {
                this.taggingData[key].map((item) => {
                    let show = false
                    if (mouseW >= item.border[0] && mouseW <= item.border[2] && mouseH >= item.border[1] && mouseH <= item.border[3]) {
                        if (item.inTag(new Point(mouseW, mouseH))) {
                            show = true;
                            hasInter = true
                        }
                    }
                    if (show) {
                        item.highLight = true
                        item.showTitle = true
                    } else {
                        item.highLight = false
                        item.showTitle = false
                    }
                })
            }
        })
        if (hasInter) {
            this.el.style.cursor = "pointer"
        } else {
            this.el.style.cursor = "default"
        }
    }

    //可移除的检测鼠标是否在标注中的鼠标移动事件
    checkPointMouseMoveEvent_ = this.checkPointMouseMoveEvent.bind(this)

    //检测鼠标是否在标注中的鼠标移动事件
    checkPointMouseClickEvent(e) {
        let mouseW = e.offsetX;
        let mouseH = e.offsetY;
        Object.keys(this.taggingData).forEach((key) => {
            if (this.taggingData[key] && this.taggingData[key] instanceof Array) {
                this.taggingData[key].map((item) => {
                    if (mouseW >= item.border[0] && mouseW <= item.border[2] && mouseH >= item.border[1] && mouseH <= item.border[3]) {
                        if (item.inTag(new Point(mouseW, mouseH))) {
                            if (this.showTypeCallback) {
                                this.showTypeCallback(item.id)
                            }
                        }
                    }
                })
            }
        })
    }

    //可移除的检测鼠标是否在标注中的鼠标移动事件
    checkPointMouseClickEvent_ = this.checkPointMouseClickEvent.bind(this)

    //绑定调用者鼠标移动事件
    setMouseMoveFunction(callback) {
        this.showTypeCallback = callback
    }

    //注册基础事件
    registerBaseEvent() {
        //窗口变化
        window.addEventListener("resize", this.windowResize.bind(this), false);
        //滚轮事件
        this.el.addEventListener("wheel", this.mouseWheelEvent.bind(this), false);
        //鼠标按下事件
        this.el.addEventListener("mousedown", this.mouseDownEvent.bind(this), false);
        //查看模式，移动鼠标时检测点位是否在标注中
        if (this.showType) {
            this.el.addEventListener("mousemove", this.checkPointMouseMoveEvent_, false);
            this.el.addEventListener("click", this.checkPointMouseClickEvent_, false)
        }
    }

    //清楚视图内所有东西
    clearAllCanvas() {
        this.ctx.clearRect(0, 0, this.el.width, this.el.height)
    }

    //切换标注工具
    changeToolType(type) {
        this.toolType = type
        this.dragEnable = true
        this.tempIds = {
            rect: "",
            round: "",
            polygon: ""
        };
        if (type != 0) {
            this.dragEnable = false;
        }
        if (type == 3) {
            Notification({ title: '提示', message: '点击鼠标进行标点，按X键即可结束标点', duration: 4000 })
        }
    }

    //获取临时标注数据
    getTempDataById(id, type) {
        let res = null;
        Object.keys(this.tempTaggingData).forEach((item) => {
            if (item != type) {
                this.tempTaggingData[item] = [];
            }
        })
        this.tempTaggingData[type] = this.tempTaggingData[type].filter(item => item.id == id)
        this.tempTaggingData[type].map((item) => {
            if (item.id == id) {
                res = item
                return
            }
        })
        return res;
    }

    //重设配置
    resetTaggingConfig(taggingConfig) {
        if (taggingConfig.color) {
            this.taggingConfig.color = taggingConfig.color
        }
        if (taggingConfig.width) {
            this.taggingConfig.width = taggingConfig.width
        }
    }

    //删除临时数据
    deleteTempData(id, type) {
        Object.keys(this.tempTaggingData).forEach((item) => {
            if (item != type) {
                this.tempTaggingData[item] = [];
            }
        })
        this.tempTaggingData[type] = this.tempTaggingData[type].filter(item => item.id != id)
    }

    //保存后，临时数据存入正式标注数据
    tempTaggingToData(id, type, data) {
        this.tempTaggingData[type].map((item) => {
            if (item.id == id) {
                item.id = data.objid
                item.createdT = data.createdT
                this.taggingData[type].push(item)
            }
        })
        this.tempTaggingData[type].filter(item => item.id != id);
    }

    //高亮显示
    showHighLight(id) {
        let temp = this.taggingData
        if (temp) {
            Object.keys(temp).forEach((key) => {
                temp[key].map((item) => {
                    if (item.id == id) {
                        item.highLight = true
                        item.showTitle = true
                    } else {
                        item.highLight = false
                        item.showTitle = false
                    }
                })
            })
        }
    }

    //取消高亮
    cancelHighLight() {
        let temp = this.taggingData
        if (temp) {
            Object.keys(temp).forEach((key) => {
                temp[key].map((item) => {
                    item.highLight = false
                    item.showTitle = false
                })
            })
        }
    }

    //恢复至默认宽高
    fixToAutoWH() {
        this.offset = [0, 0]
        this.scale = [1, 1]
        this.windowResize()
    }

    //删除正式标注信息
    deleteTaggingData(id) {
        Object.keys(this.taggingData).forEach((key) => {
            this.taggingData[key] = this.taggingData[key].filter(item => item.id != id)
        })
        Object.keys(this.tempTaggingData).forEach((key) => {
            this.tempTaggingData[key] = this.tempTaggingData[key].filter(item => item.id != id)
        })
    }

    //canvas转base64图
    canvasToBase64() {
        window.clearInterval(this.interval);
        this.fixToAutoWH();
        this.drawAllPage();
        let res = this.el.toDataURL(1);
        this.interval = setInterval(this.drawAllPage.bind(this), this.time)
        return res;
    }
}